package com.yomahub.liteflow.example.controller.sse;

import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@Controller
@RequestMapping(value = "/sse")
@Slf4j
public class SSEPlusController {
    private static Map<String, SseEmitter> cache = new ConcurrentHashMap<>();
    String clientId = "a";

    @RequestMapping(value = "/sseget", produces = "text/event-stream;charset=UTF-8")
    public void push(HttpServletResponse response) {
        response.setContentType("text/event-stream");

        response.setCharacterEncoding("utf-8");
        int i = 0;
        while (true) {
            try {
                Thread.sleep(1000);
                PrintWriter pw = response.getWriter();
                // 注意返回数据必须以data:开头，"\n\n"结尾
                pw.write("data:xdm帅气值加" + i + "\n\n");
                pw.flush();
                // 检测异常时断开连接
                if (pw.checkError()) {
                    log.error("客户端断开连接");
                    return;
                }

                if (i > 30) {

                    log.error("消息推送完成断开连接");
                    return;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            i++;
        }
    }

    // /sse/create?clientId=1
    @GetMapping("/create")
    public SseEmitter create(@RequestParam(name = "clientId", required = false) String clientId) {
        // 设置超时时间，0表示不过期。默认30000毫秒
        // 可以在客户端一直断网、直接关闭页面但未提醒后端的情况下，服务端在一定时间等待后自动关闭网络连接
        SseEmitter sseEmitter = new SseEmitter(0L);
        // 是否需要给客户端推送ID
        if (Strings.isBlank(clientId)) {
            clientId = UUID.randomUUID().toString();
        }
        this.clientId = clientId;
        cache.put(clientId, sseEmitter);
        log.info("sse连接，当前客户端：{}", clientId);
        return sseEmitter;
    }

    // @Scheduled(cron = "0/3 * * * * ?")
    // public void pushMessage() {
    //     try {
    //         sseId++;
    //         SseEmitter sseEmitter = cache.get(clientId);
    //         sseEmitter.send(SseEmitter.event().data("帅气值暴增" + sseId).id("" + sseId).reconnectTime(3000));
    //     } catch (Exception e) {
    //         log.error(e.getMessage());
    //         sseId--;
    //     }
    // }
    @GetMapping("/push")
    public void push() {
        int i = 0;
        SseEmitter sseEmitter = cache.get(clientId);
        // 注册代码以在异步请求完成时调用。当异步请求由于包括超时和网络错误在内的任何原因而完成时，将从容器线程调用此方法。此方法可用于检测ResponseBodyEmitter实例不再可用。
        sseEmitter.onCompletion(() -> log.info("sse连接断开，当前客户端：{}", clientId));
        // 注册代码以在异步请求超时时调用。当异步请求超时时，从容器线程调用此方法。
        sseEmitter.onTimeout(()-> log.info("sse连接超时，当前客户端：{}", clientId));
        while (true) {
            try {
                Thread.sleep(1000);
                sseEmitter.send(SseEmitter.event().data("帅气值暴增" + i).id("" + i).reconnectTime(3000));
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            i++;
        }
    }

    @GetMapping("/close")
    public void close(@RequestParam(name = "clientId", required = false) String clientId) {
        SseEmitter sseEmitter = cache.get(clientId);
        if (sseEmitter != null) {
            sseEmitter.complete();
            cache.remove(clientId);
        }
    }
}